import sqlite3
import random
from sklearn.cluster import KMeans
import numpy as np
import argparse
import os

def parse_args():
    parser = argparse.ArgumentParser(description='input zero-cov.')
    parser.add_argument('--zero', required=True, help='zero-cov.')
    parser.add_argument('--output', required=True, help='configure output.')
    parser.add_argument('--target', required=True, help='target.')
    parser.add_argument('--param', required=True, help='param.')
    return parser.parse_args()

def count_function_occurrences(zero_filename):
    file_function_counts = {}

    with open(zero_filename, 'r') as zero_file:
        current_file = None
        for line in zero_file:
            line = line.strip()
            if line.startswith('File:'):
                # 提取文件名
                current_file = line.split('File: ')[1].rsplit('/', 1)[-1]
                # 如果文件名尚未出现在字典中，初始化其字典
                if current_file not in file_function_counts:
                    file_function_counts[current_file] = {}
            elif line.startswith('function:'):
                # 提取函数名
                function_name = line.split(': ')[1].strip('()')
                # 如果函数名在当前文件中尚未出现，初始化其计数器
                if function_name not in file_function_counts[current_file]:
                    file_function_counts[current_file][function_name] = 0
                # 增加函数计数
                file_function_counts[current_file][function_name] += 1

    return file_function_counts



def count_matching_functions(file_function_counts_pos, file_function_counts_zero):
    total_matches = 0

    # 遍历pos字典中的文件
    for file_name ,functions in file_function_counts_pos.items():
        # 如果文件名也存在于zero字典中
        if file_name in file_function_counts_zero:
            functions_zero = file_function_counts_zero[file_name]
            matching_functions = set(file_function_counts_pos[file_name].keys()).intersection(set(functions_zero.keys()))
            total_matches += len(matching_functions)

    return total_matches

# match=count_matching_functions(zero_fun,pos_fun)
# print(match)

def find_function(zero_fun,target):
    param_list = []
    conn = sqlite3.connect(f"/home/cura/Documents/173/{target}/param_relation_2.db")
    cursor = conn.cursor()
    cursor.execute("SELECT ID,param1 FROM coverage WHERE param2 IS NULL")
    params = cursor.fetchall()
    for row in params:
        ID = row[0]  # 第一列是ID
        param1_value = row[1] 
        pos_fun=count_function_occurrences(f"/home/cura/Documents/173/{target}/{ID}/cov/pos-cov")
        match=count_matching_functions(zero_fun,pos_fun)
        param_list.append([ID,match])

    conn.commit()
    conn.close()
    return param_list

def recomment_config(initial_param,target):
    selected=[initial_param]
    conn = sqlite3.connect(f"/home/cura/Documents/173/{target}/param_relation_2.db")
    cursor = conn.cursor()
    cursor.execute("SELECT param1 FROM coverage WHERE param2 IS NULL")
    param_list=[row[0] for row in cursor.fetchall()]

  

    while param_list:
        param_list=[item for item in param_list if item not in selected]
        elements_to_check = selected.copy()  # 保存当前的 selected 列表状态
        
        for element in elements_to_check:

            cursor.execute("SELECT param1,param2 FROM coverage_analysis WHERE param1 = ? AND ab_edges <= a_edges", (element,))
                
                # 获取查询结果
            results = cursor.fetchall()
            param2_values = {item[1] for item in results}  # 使用集合去除重复值

# 从 param_list 中排除所有在 param2_values 中的值
            param_list = [item for item in param_list if item not in param2_values]
                # 添加结果到 selected 中，如果它们不在 selected 中并且至少有一个结果
        if not param_list:
            break
        weight_list=[]
        for param in param_list:
            cursor.execute("SELECT a_edges,ab_edges FROM coverage_analysis WHERE param1 IS ? AND param2 IS ?",(selected[-1],param))
            edges_result=cursor.fetchone()
    
            weight_list.append([param,edges_result[1]-edges_result[0]])
        weights = [item[1] for item in weight_list]

# 根据权重选择一个元素
        selected_element = random.choices(weight_list, weights=weights, k=1)[0][0]
        selected.append(selected_element)
    conn.commit()
    conn.close()
    return selected


def main():
    args = parse_args()

    # Convert relative paths to absolute paths
    zero_fun = count_function_occurrences(os.path.abspath(args.zero))
    output=os.path.abspath(args.output)
    selected_states = []
    conn = sqlite3.connect(f"/home/cura/Documents/173/{args.target}/param_relation_2.db")
    cursor = conn.cursor()
    cursor.execute("SELECT param1, edges FROM coverage WHERE param2 IS NULL")
    params = cursor.fetchall()
    edges_list = [row[1] for row in params]

    # 转换为 numpy 数组，以便 scikit-learn 处理
    edges_array = np.array(edges_list).reshape(-1, 1)
    # 使用 K-means 进行聚类，假设我们已经知道类别数，这里假设为2
    kmeans = KMeans(n_clusters=2, n_init='auto')
    kmeans.fit(edges_array)

    # 计算每个聚类的平均值
    cluster_centers = kmeans.cluster_centers_
    cluster_means = cluster_centers.mean(axis=1)

    # 找到平均值最低的聚类cursor.execute("SELECT param1,param2,a_edges,ab_edges FROM coverage_analysis WHERE param1 IS ? AND ab_edges > a_edges", (element,))
    lowest_mean_cluster = np.argmin(cluster_means)

    # 根据聚类结果，将属于平均值最低聚类的所有 edges 设置为 0
    for i, cluster in enumerate(kmeans.labels_):
        if cluster == lowest_mean_cluster:
            params[i] = (params[i][0], 0)  # 更新 params 列表中的 edges 值


    #zero_fun=count_function_occurrences("/home/cura/Documents/173/test/Sconf/cov/zero-cov")
    function_list=find_function(zero_fun,args.target)


    vector1 = [element[1] for element in function_list]
    vector2 = [element[1] for element in params]
    vector = [a * b for a, b in zip(vector1, vector2)]


    sum_element=sum(vector)
 
    initial_list = []
    ID = 1
    for element in vector:
        initial_pro=element/sum_element
        initial_list.append([ID,initial_pro])
        ID+=1
    #print(initial_list)
    
    selected_item = random.choices(initial_list, weights=[item[1] for item in initial_list], k=1)[0]
    cursor = conn.cursor()
    cursor.execute("SELECT param1 FROM coverage WHERE ID IS ?",(selected_item[0],))
    param = cursor.fetchone()

    re=recomment_config(param[0],args.target)
    configure=' '.join(re).strip()+' @@'
    print(configure) 
    conn.commit()
    conn.close()
    #with open(os.path.join(output,'config.txt'),'a') as file:
    with open(output,'a') as file:
    	file.write(configure+'\n')
if __name__ == "__main__":
    main()
       
            
        
